package services;

import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import repositories.EventRepository;
import domain.Administrator;
import domain.Challenge;
import domain.Event;
import domain.Registration;
import domain.Route;

@Service
@Transactional
public class EventService {

	// Managed repository

	@Autowired
	private EventRepository eventRepository;

	// Supporting services

	@Autowired
	private AdministratorService administratorService;

	@Autowired
	private ParticipantService participantService;

	// Constructors

	public EventService() {
		super();
	}

	// Simple CRUD methods

	public Event create() {

		Collection<Route> routes = new HashSet<Route>();
		Collection<Registration> registrations = new HashSet<Registration>();
		Collection<Challenge> challenges = new HashSet<Challenge>();
		Administrator administrator = administratorService.findByPrincipal();

		String referenceNumber;

		Date creationMoment = new Date();

		String code = UUID.randomUUID().toString();
		referenceNumber = administrator.getSurname() + code;
		Event result = new Event();

		result.setAdministrator(administrator);
		result.setRoutes(routes);
		result.setRegistrations(registrations);
		result.setChallenges(challenges);
		result.setRating(0.0);
		result.setReferenceNumber(referenceNumber);
		result.setCreationMoment(creationMoment);

		return result;
	}

	public Event findOne(int eventId) {
		Assert.isTrue(eventId != 0);
		Event result;
		result = eventRepository.findOne(eventId);
		Assert.notNull(result);

		return result;
	}

	public Collection<Event> findAllEvent() {
		Collection<Event> result;
		result = eventRepository.findAll();
		Assert.notNull(result);

		return result;
	}

	public void save(Event event) {
		Assert.notNull(event);
		Date currentMoment = new Date(System.currentTimeMillis() - 1);
		Assert.isTrue(event.getAdministrator().equals(
				administratorService.findByPrincipal()));
		Assert.isTrue(event.getStartMoment().after(currentMoment));
		Assert.isTrue(event.getFinishMoment().after(event.getStartMoment()));
		if (event.getId() != 0) {
			Assert.isTrue(event.getRegistrations().isEmpty());
		}

		eventRepository.save(event);
	}

	public void delete(Event event) {
		Assert.isTrue(eventRepository.exists(event.getId()));
		Assert.isTrue(event.getRegistrations().isEmpty());
		Assert.isTrue(event.getAdministrator().equals(
				administratorService.findByPrincipal()));
		
		eventRepository.delete(event);
	}

	// Other business methods

	public Collection<Event> findEventsAvailable() {
		Collection<Event> result;
		Date currentMoment;

		currentMoment = new Date();
		result = eventRepository.findEventsAvailable(currentMoment);
		Assert.notNull(result);

		return result;
	}

	public Collection<Event> findEventsOngoing() {
		Collection<Event> result;
		Date currentMoment;

		currentMoment = new Date();
		result = eventRepository.findEventsOngoing(currentMoment);
		Assert.notNull(result);

		return result;
	}

	public Collection<Event> findEventsByAdministrator() {
		Collection<Event> result;
		result = eventRepository.findEventsByAdministrator(administratorService
				.findByPrincipal().getId());
		Assert.notNull(result);
		return result;
	}

	public Collection<Event> findAllOrderedByRating() {
		Collection<Event> result;
		result = eventRepository.findAllOrderedByRating();
		Assert.notNull(result);
		return result;
	}

	public Collection<Event> findEventsByParticipant() {
		Collection<Event> result;
		result = eventRepository.findEventsByParticipant(participantService
				.findByPrincipal().getId());
		Assert.notNull(result);
		return result;
	}

	public Collection<Event> findEventsOngoingByAdministrator() {
		Collection<Event> result;
		result = eventRepository.findEventsOngoingByAdministrator(new Date(),
				administratorService.findByPrincipal().getId());
		Assert.notNull(result);
		return result;
	}

	public Collection<Event> findByAdministratorOrderedByRating(int id) {
		Collection<Event> result;
		result = eventRepository.findByAdministratorOrderedByRating(id);
		Assert.notNull(result);
		return result;
	}

	public Collection<Event> findByParticipantOrderedByRating(int id) {
		Collection<Event> result;
		result = eventRepository.findByParticipantOrderedByRating(id);
		Assert.notNull(result);
		return result;
	}
}
